#! /usr/bin/env python3
# -*- coding: UTF-8 -*-
# ----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# CANN Open Software License Agreement Version 2.0 (the "License").
# Please refer to the License for details. You may not use this file except in compliance with the License.
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
# See LICENSE in the root of the software repository for the full text of the License.
# ----------------------------------------------------------------------------------------------------------
import os
import sys
import shutil
import unittest
import subprocess
import math
from unittest.mock import MagicMock, Mock, patch

THIS_FILE_NAME = __file__
FILE_PATH = os.path.dirname(os.path.realpath(THIS_FILE_NAME))
ASCENDUMP_PATH = os.path.join(FILE_PATH, "../../../../", "utils/show_kernel_debug_data")
print(ASCENDUMP_PATH)
sys.path = [ASCENDUMP_PATH] + sys.path
from show_kernel_debug_data import dump_logger, dump_parser, data_converter
from show_kernel_debug_data.dump_parser import DumpBinFile


class TestAscendump(unittest.TestCase):
    def setUp(self):
        # 每个测试用例执行之前做操作
        print("---------------------set up case----------------------------------")

    def tearDown(self):
        # 每个测试用例执行之后做操作
        print("---------------------tear down case-------------------------------")

    def _make_out_dir(self, out_dir_name):
        out_dir = os.path.join(FILE_PATH, out_dir_name)
        if not os.path.exists(out_dir):
            os.mkdir(out_dir)
        return out_dir

    def _clean_out_dir(self, out_dir_name):
        out_dir = os.path.join(FILE_PATH, out_dir_name)
        if os.path.exists(out_dir):
            shutil.rmtree(out_dir)

    def test_ascendump_log_file(self):
        output_path = self._make_out_dir("test_ascendump_log_file")
        asd_logger = dump_logger.DumpParserLog()
        asd_logger.set_log_file(os.path.join(os.path.abspath(output_path), "test_ascendump_log_file.log"))
        self.assertTrue(os.path.join(os.path.abspath(output_path), "test_ascendump_log_file.log"), asd_logger.get_log_file)


    def test_ascendump_parser_file(self):
        output_path = self._make_out_dir("test_ascendump_parser_file")
        test_dump_file = os.path.join(output_path, "test_dump_file.bin")
        with open(test_dump_file, 'wb+') as f:
            f.seek(0)
            content = b'\x00'
            f.write(content)
        with patch('sys.argv', ["show_kernel_debug_data", "./xx.bin", "./out"]), \
                patch('sys.exit'),\
                    self.assertRaises(RuntimeError):
            dump_parser.execute_parse()
        with patch('sys.argv', ["show_kernel_debug_data", test_dump_file, "./out"]), \
                patch('sys.exit'),\
                    self.assertRaises(RuntimeError):
            dump_parser.execute_parse()

        args = ["show_kernel_debug_data", "-h"]
        with patch('sys.argv', args), \
                patch('sys.exit'), patch('show_kernel_debug_data.dump_parser.parse_dump_bin'):
            dump_parser.execute_parse()
            dump_parser.parse_dump_bin.assert_not_called()


    @patch('show_kernel_debug_data.dump_parser.DumpBinFile.show_print')
    @patch('show_kernel_debug_data.dump_parser.get_install_path')
    def test_parse_dump_shape(self, get_install_path_mock, show_mock):
        get_install_path_mock.return_value  = ""
        from glob import glob
        data_path = self._make_out_dir("test_parse_dump_shape")
        test_dump_file = os.path.join(data_path, "test_dump_file.bin")
        with open(test_dump_file, 'wb+') as f:
            f.seek(0)
            content = b'\x00\x00\x10\x00\x00\x00\x00\x00 \x00\x00\x00@\xf9\x0f\x00\xcd\xbc\xa5Z\x00\x00\x00\x00\xc0\x06 A\xc0\x12\x00\x00\x05\x00\x00\x00\x08\x00\x00\x00 \x00\x02\x00\x00\x00\x00\x00\x02\x00\x00\x00X\x00\x00\x00 \x01\x00\x00\x01\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00,N\x01Y\x10W\nV\xa0V\rXbW\xfeW\xc4S<VgX4X\xd1L\xd2T\x0cX\tL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00X\x00\x00\x00`\x01\x00\x00\x01\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x16Y\xe1V\xe4U\xa9T\xe4R,W\tXEXWTVW\x17V\xecX!YXVjWZY\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00X\x00\x00\x00 \x01\x00\x00\x01\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x82U,UXW2X(V\x16W+T!X\xb8U\x82VQU\xc5T8T\x9cX\xaaY\xf6Q\x18VfV\xd4V\x7fU\xe2V\xedVNVVU\x0eQ1L\xc9T\x83W\xccV\xa6KpX\x18W\x02\x00\x00\x00X\x00\x00\x00`\x01\x00\x00\x01\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xf0X\xc6U\x9bUjTjR@X\x1aV(W\x97R^W\x9bX\xb6W5N\xf6T^W\xe2U\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00X\x00\x00\x00 \x01\x00\x00\x01\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00RU\xa6WKV\nZxPwU:VyU\xa1T\x01X\x9eT\xdcU\xdcU\xdeVMV\x88U\xd2UZQdX\xcfT\xd9UNU&W\x17W\x84WlX\x1aV\x9fUIX\xbcU\xdaV\x12U\x02\x00\x00\x00X\x00\x00\x00`\x01\x00\x00\x01\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01U\xd6S&T\xc4V\xbaW\xf6V\xa5X\xabU\xebVnU?V\x94X\xf0V\xaaR\xe5P\x08X\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00X\x00\x00\x00 \x01\x00\x00\x01\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x19U\x80X\xe6V\xecM\xdaV\x80U\x88O\x17Y\xf7V\xceU\xabQDO<Y1W\xceU\x13V$WkT\x85V\xaaVlU\xe4XCR(X\x88TxT{T\x89U\xa8T9Y\xb2Y8X\x02\x00\x00\x00X\x00\x00\x00`\x01\x00\x00\x01\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00ST\xd8X\xb3Q\x00X\x00Z(U\xfaW&X\x1eX$R\xa1X\x1eX\xccX\x8eSTV\x08T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00X\x00\x00\x00 \x01\x00\x00\x01\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x14YjT\x06V\x8bR\xc0X\x1fY ZsU\x12YLKdX\nXLX\xe1T\'U\tT\xfdX\xaaY\xd7V\xd2Y8X\xd9VrXLV\x90V\x90XuP\x7fX>U\x18U7V\x19Y\x02\x00\x00\x00X\x00\x00\x00`\x01\x00\x00\x01\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x1eU\xe8X\xe2U\xe4V\x0bM*Y\x7fV`X\x0eX\xa6W\xe1XKY"XTW\x8cU#M\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00X\x00\x00\x00 \x01\x00\x00\x01\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xb6T[U\xa5X\xceX>Q\xa9X\xebT*T-U\x04Y\xfaU\x07V\xcaWnF\xcaV&TZV Y\xe5S\xb2U\x88YAQdVHQKY\xd8W\xb0XdU\xe5L\x06V\xe2P\xb2T\x02\x00\x00\x00X\x00\x00\x00`\x01\x00\x00\x01\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xe8V\x0bT\xa8R\xa2Y\xeaOMVIU\x88X\xd8R\x84S\x8eW\x1cSYV~Y:RlL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00X\x00\x00\x00 \x01\x00\x00\x01\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xfbU\x1cV\xaeX#U\xf4VAT\x0cT\x02Y\xb5G\xf0X\xc0V\x04VcR\x00X U\x9fN\xfbU\x86PVY\x06Z\x84TTT\x9cYWVdW\x8fWaTxV\x11W\xbeV\xd0TjU\x02\x00\x00\x00X\x00\x00\x00`\x01\x00\x00\x01\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x93X\x01U)M?R\xe7W\x8dV|L\xaeX\xbfU\x98Y\xdcU*Y\xb0X\xecS\x93T\xa5X\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00X\x00\x00\x00 \x01\x00\x00\x01\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x1eW\x86UiSXV\xb5VaU\x06M\x80W\xb8X\xf2U,W\xbaQ^VbX\x92X\x94T\xebXdX8U\xd6U2Y\xe6V2X\'X\x80U0X\xc5RqV\xe2V7SvT2R\x02\x00\x00\x00X\x00\x00\x00`\x01\x00\x00\x01\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x08X\xa0X\xc2W\xfeV\xc8RBT\xaaQ\xe5UBU\x82V^X\xdcW\x98U\x7fOhX\x88R\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00X\x00\x00\x00\x00`\x02\xc0\x01\x00\x00\x00\x9a\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 V\xacT\x04Y\xb1Y\xc0X<W\xe7SYO\xdcW)W"X[WQXFV\x92Q\xbfX,N\x01Y\x10W\nV\xa0V\rXbW\xfeW\xc4S<VgX4X\xd1L\xd2T\x0cX\tL\x00'
            f.write(content)

        with patch('sys.argv', ["show_kernel_debug_data", test_dump_file, data_path]):
            dump_parser.parse_dump_bin(test_dump_file, data_path)
            show_mock.assert_called_once()
        self.assertTrue(os.path.exists(test_dump_file))


    @patch('show_kernel_debug_data.dump_parser.DumpBinFile.show_print')
    @patch('show_kernel_debug_data.dump_parser.get_install_path')
    def test_parse_time_stamp(self, get_install_path_mock, show_mock):
        get_install_path_mock.return_value = ""
        from glob import glob
        data_path = self._make_out_dir("test_parse_time_stamp")
        test_dump_file = os.path.join(data_path, "test_dump_file.bin")
        with open(test_dump_file, 'wb+') as f:
            f.write( b'\x00' * 1024 * 1024)
        with open(test_dump_file, 'r+b') as f:
            f.seek(0)
            content = b'\x00\x00\x10\x00\x00\x00\x00\x00\x01\x00\x00\x00\xf0\xfe\x0f\x00\xcd\xbc\xa5Z\x00\x00\x00\x00\x10\x01 A\xc0\x12\x00\x00\x05\x00\x00\x00\x08\x00\x00\x00\x01\x00\x02\x00\x00\x00\x00\x00\x06\x00\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0,P?\xb77\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x18\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00,-P?\xb77\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x18\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00=-P?\xb77\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x18\x00\x00\x00\xd0\x07\x00\x00\x00\x00\x00\x00A-P?\xb77\x00\x00\x80\x03\x00\x00@\x12\x00\x00\x06\x00\x00\x00\x18\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00R-P?\xb77\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x18\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00[-P?\xb77\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x18\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00h-P?\xb77\x00\x00\x00\x00'
            f.write(content)

        args = ["show_kernel_debug_data", test_dump_file, data_path]
        with patch('sys.argv', args), \
                patch('sys.exit') :
            dump_parser.parse_dump_bin(test_dump_file, data_path)
            show_mock.assert_called_once()
        self.assertTrue(os.path.exists(test_dump_file))

    @patch('show_kernel_debug_data.dump_parser.DumpBinFile.show_print')
    @patch('show_kernel_debug_data.dump_parser.get_install_path')
    @patch('glob.glob')
    @patch("subprocess.run")
    def test_pre_process(self, run_mock, glob_mock, get_install_path_mock, show_mock):
        get_install_path_mock.return_value = ""
        from glob import glob
        data_path = self._make_out_dir("test_parse_time_stamp")
        test_dump_file = os.path.join(data_path, "test_dump_file.bin")
        with open(test_dump_file, 'wb+') as f:
            f.write(b'\x00' * 1024 * 1024)
        with open(test_dump_file, 'r+b') as f:
            f.seek(0)
            content = b'\x00\x00\x10\x00\x00\x00\x00\x00H\x00\x00\x00\x08\xfe\x0f\x00\xcd\xbc\xa5Z\x00\x00\x00\x00\xf8\x01\x80E\xc0\x12\x00\x00\x05\x00\x00\x00\x08\x00\x00\x00\x18\x00\x02\x01\x00\x00\x00\x00\x06\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\xb8(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x005\xba(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00:\xba(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00;\xba(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00K\xba(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x00\x91\x00\x00\x00\x00\x00\x00\x00Y\xbb(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x00d\x00\x00\x00\x00\x00\x00\x00\xad\xbb(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x00c\x00\x00\x00\x00\x00\x00\x00\xbb\xbb(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x00e\x00\x00\x00\x00\x00\x00\x00\xbc\xbb(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\xdd\xbb(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\xe1\xbb(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\xe4\xbb(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\xf0\xbb(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\xf4\xbb(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\xf7\xbb(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\xfa\xbb(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\x02\xbc(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\x05\xbc(\x07\xd0\xe4\x00\x00\x06\x00\x00\x00\x10\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\x0b\xbc(\x07\xd0\xe4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
            f.write(content)
        glob_mock.return_value = [test_dump_file]
        dump_file = DumpBinFile(test_dump_file)
        self.assertEqual(os.path.basename(dump_file.dump_bin), "test_dump_file.bin")
        run_mock.assert_called_once()


    def test_data_converter_bf16(self):
        self.assertEqual(data_converter.decode_bfloat16(123), 1.1295766027432919e-38)
        self.assertEqual(data_converter.decode_bfloat16(123123), -1.400799628097319e+20)
        self.assertEqual(data_converter.decode_bfloat16(0x3f80), 1)
        self.assertEqual(data_converter.decode_bfloat16(0xc000), -2)
        self.assertEqual(data_converter.decode_bfloat16(0x7f7f), 3.3895313892515355e+38)
        self.assertEqual(data_converter.decode_bfloat16(0x0080), 1.1754943508222875e-38)
        self.assertEqual(data_converter.decode_bfloat16(0x0000), 0)
        self.assertEqual(data_converter.decode_bfloat16(0x8000), 0)
        self.assertTrue(math.isnan(data_converter.decode_bfloat16(0xffc1)))
        self.assertTrue(math.isnan(data_converter.decode_bfloat16(0xff81)))
        self.assertTrue(math.isinf(data_converter.decode_bfloat16(0x7f80)) and data_converter.decode_bfloat16(0x7f80) > 0)
        self.assertTrue(math.isinf(data_converter.decode_bfloat16(0xff80)) and data_converter.decode_bfloat16(0xff80) < 0)


if __name__ == "__main__":
    unittest.main()
